
#include <sys/wait.h>   /* for wait3 */
#include "pty_shell.hpp"
#include "io_session.hpp"
#include "ipc_session.hpp"
#include "server_per_cpu.hpp"

#include "vty_manager.hpp"
#include "command_manager.hpp"

void init_sigaction();
void catch_sigchld(int signo);


typedef server_per_cpu<io_session_ptr, command_manager> cmd_db_server;
typedef boost::shared_ptr<cmd_db_server> cmd_db_server_ptr;

typedef server_per_cpu<io_session_ptr, vty_manager> vty_server;
typedef boost::shared_ptr<vty_server> vty_server_ptr;

int main() 
{
    command_manager_ptr cmdmng = command_manager::instance();
    vty_manager_ptr vtymng = vty_manager::instance();
    vty_dft_command _dftcmd(*cmdmng);

    init_sigaction();

    _dftcmd.build();

    // Block all signals for background thread.
    sigset_t new_mask;
    sigfillset(&new_mask);
    sigset_t old_mask;
    pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);

    tcp::endpoint endpoint(tcp::v4(), 8888);
    cmd_db_server_ptr server(
            new cmd_db_server(8, *cmdmng, endpoint));
    boost::thread t(boost::bind(&cmd_db_server::run, server));

    tcp::endpoint vtyep(tcp::v4(), 8080);
    vty_server_ptr vtyserv(
            new vty_server(8, *vtymng, vtyep));
    boost::thread vtythread(boost::bind(&vty_server::run, vtyserv));

    boost::thread cmdmng_thread(boost::bind(&command_manager::run, cmdmng));


    pthread_sigmask(SIG_SETMASK, &old_mask, 0);

    // Wait for signal indicating time to shut down.
    sigset_t wait_mask;
    sigemptyset(&wait_mask);
    sigaddset(&wait_mask, SIGINT);
    sigaddset(&wait_mask, SIGQUIT);
    sigaddset(&wait_mask, SIGTERM);
    pthread_sigmask(SIG_BLOCK, &wait_mask, 0);
    int sig = 0;
    sigwait(&wait_mask, &sig);


    // Stop the server.
    cmdmng->stop();
    server->stop();
    vtyserv->stop();

    cmdmng_thread.join();
    t.join();
    vtythread.join();


    //cmd_db_server_ptr server(new cmd_db_server());
    return 0;
}

void catch_sigchld(int signo) 
{ 
    int sts;
    pid_t pid = wait3(&sts, WNOHANG, NULL);
    pty_manager::remove(pid);
    PDBG("###( Parent ) catch SIGCHLD (%d)\n", pid);
}

void init_sigaction()
{
    struct sigaction sact;
    sact.sa_flags = 0|SA_NODEFER;
    sigemptyset(&sact.sa_mask);

    sact.sa_handler = catch_sigchld;
    sigaction(SIGCHLD, &sact, NULL);

}
